﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Collections;
using System.Reflection;
using Common;
using LoginServer.Converter;

namespace LoginServer
{
    public partial class ManagerUserConnection
    {
        Socket sock;
        IPAddress ipServer;
        int portServer;
        bool isStart;
        Hashtable Users;
        CONFIG config;
        LoginServer login_server;
        YAuthentication authentication;
        ConvertDataUser convert_data;
        public ManagerUserConnection(string ip,int port,CONFIG config,LoginServer login_server)
        {
            this.ipServer = IPAddress.Parse(ip);
            this.portServer = port;
            this.config = config;
            this.login_server = login_server;
            IPEndPoint endpoint = new IPEndPoint(ipServer,portServer);
            try
            {
                sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                sock.Bind(endpoint);
            }
            catch(Exception e)
            {

            }

            Init();
        }
        public Hashtable getAllUser()
        {
            return Users;
        }
        public void Init()
        {            
            Users = new Hashtable();
            authentication = new YAuthentication();
            convert_data = new ConvertDataUser();
            isStart = false;
        }

        public void Start()
        {
            isStart = true;
            sock.Listen(config.MAX_USER_CONNECTION);
            sock.BeginAccept(new AsyncCallback(AcceptUser), sock);        
            Print("Port to User connect at port = "+ portServer.ToString() +" Open!");
            Print("Waiting Accept User...");
        }

        void AcceptUser(IAsyncResult ar)
        {
            try
            {
                if(!ar.IsCompleted)
                {
                    sock.BeginAccept(new AsyncCallback(AcceptUser), sock);
                    return;
                }
                Socket client = sock.EndAccept(ar);
                if (!CheckMaxConnect())
                {
                    client.Disconnect(true);
                    client = null;
                    sock.BeginAccept(new AsyncCallback(AcceptUser), sock);
                    return;
                }
                User new_user = new User(Users.Count,client);               
                IPEndPoint endpoint = (IPEndPoint)client.RemoteEndPoint;
                Print("New User Connected " + endpoint.Address.ToString()+":"+ endpoint.Port.ToString());
                new_user.XSocketReceive += new User.XSocketReciveHandler(new_user_XSocketReceive);
                new_user.XSocketDisconnected += new User.XSocketDisconnectedHandler(new_user_XSocketDisconnected);
                sock.BeginAccept(new AsyncCallback(AcceptUser), sock);               
                new_user.BeginCheckCode(authentication);

            }
            catch (System.Exception e)
            {
                Console.WriteLine("error: "+e.Message);
            }
        }     

        

        public void RemoveClient(User client)
        {
            NotifyUser(false, client.User_Name, client.User_ID);
            int id = client.User_ID;
            //Console.WriteLine("Remove Client ID = {0}", id);
            client.StopAll();
            login_server.AccessDB.Logout(id);
            Users.Remove(id);
            client = null;
        }

        void Print(string text)
        {
            Console.WriteLine(text);
        }

        void new_user_XSocketReceive(object sender, XSocketReciveEventArgs args)
        {
            MSG_GSM message = (MSG_GSM)args.Data[0];            
            //Console.WriteLine("Receive: " + message.ToString());
            List<object> param = new List<object>();
            param.Add(args.user);
            for (int i = 1; i < args.Data.Length; i++)
            {
                param.Add((byte)args.Data[i]);
            }
            try
            {
                Type t = typeof(ManagerUserConnection);
                MethodInfo handler = t.GetMethod("Process_" + message.ToString(), BindingFlags.NonPublic | BindingFlags.Instance);
                handler.Invoke(this, new object[] { param.ToArray() });
            }
            catch (System.Exception ex)
            {
                Console.WriteLine("Error MSG_GSM." + message.ToString() + "  " + ex.Message);
            }     
        }        

        void new_user_XSocketDisconnected(object sender, XSocketDisconnectEventArgs args)
        {
            if (login_server.manager_room.CheckRoomID(args.user.info.RoomID))
            {
                Room room = login_server.manager_room.GetRoom(args.user.info.RoomID);
                if (room.CheckUserInRoom(args.user.User_ID))
                {
                    if (room.CheckUserInTable(args.user.User_ID))
                    {
                        login_server.OutTable(args.user.User_ID, args.user.info.TableID);
                    }
                    login_server.OutRoom(args.user.User_ID, args.user.info.RoomID);
                }
            }
            foreach (var i in args.user.info.friends)
            {
                if (!CheckUserNotIn(i.ID))
                {
                    this.GetUser(i.ID).SendMessage_L_Update_Friend_Off_OK(args.user.User_ID);
                }
            }
            RemoveClient(args.user);
        }

        public User GetUser(int ID)
        {
            return (User)Users[ID];
        }

        internal bool CheckUser(int UserID)
        {
            if (Users.ContainsKey(UserID))
                return true;
            Console.WriteLine("user not exits");
            return false;
        }


        private bool CheckUserNotIn(int UserID)
        {
            if (!Users.ContainsKey(UserID))
                return true;
            //Console.WriteLine("user exits");
            return false;
        }
    }
}
